package com.csx.base.concurrency.aqs.reentrantlock;

import com.csx.base.concurrency.util.TimeUtil;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p> what does this class do ? </p>
 *   本案例测试公平锁和非公平锁
 * <p> How does it work ?</p>
 * <p> Why does it do this ?</p>
 *
 * @author cuisongxu
 * @date 2024/12/2 周一 9:21
 */
public class ReentrantLockFairUnfairLockTest {

    private final ReentrantLock unfairLock = new ReentrantLock(false);

    private final ReentrantLock fairLock = new ReentrantLock(true);

    // 入口方法
    public void test() {

        // 测试非公平锁的情况
        Thread thread1 = new Thread(new BaseTask(unfairLock), "thread1");
        Thread thread2 = new Thread(new BaseTask(unfairLock),"thread2");
        Thread thread3 = new Thread(new BaseTask(unfairLock),"thread3");

        System.out.println("开始测试非公平锁的情况");
        thread1.start();
        try {
            // thread2等待0.5s再启动,确保thread1获取到锁。自身进入到同步队列中阻塞
            TimeUnit.MILLISECONDS.sleep(500);
            thread2.start();
            // thread3再等待0.5s再启动,确保此时thread1刚好执行完毕释放了锁，此时刚启动的thread3和被唤醒的thread2竞争锁
            // 如果是非公平锁，则可能会出现thread3获取锁的情况;
            // 如果是公平锁，则一定是thread2先获取锁
            TimeUnit.MILLISECONDS.sleep(500);
            thread3.start();
            // 等待三个线程执行完毕
            thread1.join();
            thread2.join();
            thread3.join();
            System.out.println("非公平锁测试结束");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }


        // 测试公平锁的情况
        Thread thread4 = new Thread(new BaseTask(fairLock), "thread1");
        Thread thread5 = new Thread(new BaseTask(fairLock),"thread2");
        Thread thread6 = new Thread(new BaseTask(fairLock),"thread3");

        System.out.println("开始测试公平锁的情况");
        thread4.start();
        try {
            // thread2等待0.5s再启动,确保thread1获取到锁。自身进入到同步队列中阻塞
            TimeUnit.MILLISECONDS.sleep(500);
            thread5.start();
            // thread3再等待0.5s再启动,确保此时thread1刚好执行完毕释放了锁，此时刚启动的thread3和被唤醒的thread2竞争锁
            // 如果是非公平锁，则可能会出现thread3获取锁的情况;
            // 如果是公平锁，则一定是thread2先获取锁
            TimeUnit.MILLISECONDS.sleep(500);
            thread6.start();
            // 等待三个线程执行完毕
            thread4.join();
            thread5.join();
            thread6.join();
            System.out.println("公平锁测试结束");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    static class BaseTask implements Runnable {
        private final ReentrantLock lock;

        public BaseTask(ReentrantLock lock) {
            this.lock = lock;
        }
        @Override
        public void run() {
            lock.lock();
            String nowTime = null;
            try {
                nowTime = TimeUtil.getNowTimeStr();
                System.out.println(nowTime + "  " + Thread.currentThread().getName() + " 成功获取锁");
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally {
                nowTime = TimeUtil.getNowTimeStr();
                System.out.println(nowTime + "  " +Thread.currentThread().getName() + " 释放锁");
                lock.unlock();
            }
        }
    }
}
